import {
  Injectable,
  NestInterceptor,
  ExecutionContext,
  CallHandler,
} from '@nestjs/common';
import Axios, { AxiosResponse } from 'axios';
import { Observable, of } from 'rxjs';
import { tap } from 'rxjs/operators';
import { ReturnResult } from './return-result';
import { RequestStatusCode, RequestStatusMessage } from '../constants';
import { RamApi } from './apis';

@Injectable()
export class AuthInterceptor implements NestInterceptor {
  // NOTE: 这里只能按照普通的方式注入模块，不能使用依赖注入的方式
  private readonly ramApi: RamApi = new RamApi();

  private readonly axios = Axios.create({
    timeout: 60 * 1000,
  });

  public async intercept(context: ExecutionContext, next: CallHandler<any>): Promise<Observable<any>> {
    const [reqContext, /* resContext */] = context.getArgs();

    const authToken = reqContext.headers['x-auth-token']
      || reqContext.headers['X-Auth-Token'];

    // 1. 验证 token 是否存在
    if (!authToken) {
      return of(new ReturnResult(
        RequestStatusCode.Unauthorized,
        RequestStatusMessage.Unauthorized,
        RequestStatusMessage.Unauthorized,
      ));
    }
    // 2. 验证 token
    const checkTokenRes: boolean = await this._checkTokenValid(authToken);
    if (!checkTokenRes) {
      /*  resContext.headersSent && resContext
         .status(401)
         .json(new ReturnResult(
           RequestStatusCode.Unauthorized,
           RequestStatusMessage.Unauthorized,
           RequestStatusMessage.Unauthorized,
         )); */
      return of(new ReturnResult(
        RequestStatusCode.Unauthorized,
        RequestStatusMessage.Unauthorized,
        RequestStatusMessage.Unauthorized,
      ));
    }

    return next
      .handle()
      .pipe(
        tap(() => { /**/ })
      );
  }

  private async _checkTokenValid(token: string): Promise<boolean> {
    try {
      const { data: responseData } = await this.axios.put<
        any,
        AxiosResponse<Record<string, any>, Record<string, any>>
      >(this.ramApi.getCheckUserLoginApi(token), {});
      if (responseData.data === false) {
        return false;
      }
      return true;
    } catch (e) {
      return false;
    }
  }
}
